﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using Medianamik.Core.Interfaces;

namespace Medianamik.Core
{
    public class NodeBag : KeyedCollection<Guid, Node>
    {

        protected override Guid GetKeyForItem(Node item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            return item.ID;
        }

        protected override void InsertItem(int index, Node item)
        {
            if (item != null)
            {
                base.InsertItem(index, item);
            }
        }


        /// <summary>
        /// Cherche le noeud passé en paramètre ayent le même ID
        /// Si il n'est pas trouvé, il est ajouté
        /// Sinon le Noeud existant est retourné
        /// </summary>
        /// <param name="pNode"></param>
        /// <returns></returns>
        public Node Dig(Node pNode)
        {
            if (Contains(pNode.ID))
            {
                return this[pNode.ID];
            }
            Add(pNode);
            return pNode;
        }
        public Node Dig(Guid pNodeId, Func<Guid, Node> pGetNode)
        {
            if (Contains(pNodeId))
            {
                return this[pNodeId];
            }
            var node = pGetNode(pNodeId);
            Add(node);
            return node;
        }

        public IEnumerable<Node> Dig(IEnumerable<Guid> pIDs, Func<IEnumerable<Guid>, IEnumerable<Node>> pGetMissingNodes)
        {
            var loadedNodeIds = pIDs.Where(id => Contains(id)).ToArray();
            var missingNodeIds = pIDs.Except(loadedNodeIds).ToArray();

            var missingNodes = new List<Node>();
            if (missingNodeIds.Length > 0)
            {
                missingNodes.AddRange(pGetMissingNodes(missingNodeIds));

                foreach (var node in missingNodes)
                {
                    Add(node);
                }
            }


            //On ne peut pas se fier à la liste d'ids passée en paramètres.
            //On refait la liste en fonction des noeuds retournées par GetNodes
            var nodeIds = loadedNodeIds.Union(missingNodes.Select(n => n.ID)).ToArray();

            return nodeIds.Select(id => this[id]);
        }
    }
}
